/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gtd;

import java.io.*;
import java.util.*;
import javax.swing.JTree;
import javax.swing.tree.*;
import javax.swing.JOptionPane;

/**
 *
 * @author d
 */
public class IOController {
 
    private Properties properties;
    private HashMap categories;
    private String[][] cities;
    
    /** Constructor */
    public IOController() {
        // do nothing, for now
    }
    
    // <editor-fold defaultstate="collapsed" desc="Methods">
    
    /** Writes a file from the manifest to the disk */
    public void createResource(File file, String resource) {
        try {
            file.createNewFile();
            FileOutputStream fos = new FileOutputStream(file);
            BufferedInputStream bis = new BufferedInputStream(this.getClass().getResourceAsStream(resource));
            byte[] bytes = new byte[1024];
            while (bis.available() > 0) {
                int bytesRead = bis.read(bytes);
                fos.write(bytes, 0, bytesRead);
            }
            bis.close();
            fos.close();
        }
        catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (IOException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /** Gets the users settings */
    public void loadSettings() {
        try {
            // Get the settings dir
            File settingsDir = this.getSettingsDirectory();
            // Get the properties file
            File propertiesFile = new File(settingsDir, "clmt.properties");
            // Create the properties file if it doesn't exist
            if (!propertiesFile.exists()) {
                this.createResource(propertiesFile, "/resources/clmt.properties");
            }
            // Load the properties file
            FileInputStream in = new FileInputStream(propertiesFile);
            this.properties = new Properties();
            this.properties.load(in);
            in.close();
        }
        catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (IOException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /** Gets the users settings */
    public void saveSettings() {
        try {
            // Get the settings dir
            File settingsDir = this.getSettingsDirectory();
            // Get the properties file
            File propertiesFile = new File(settingsDir, "clmt.properties");
            // Write out the properties
            FileOutputStream out = new FileOutputStream(propertiesFile);
            this.properties.store(out, "---No Comment---");
            out.close();
        }
        catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (IOException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /** Gets the users home directory */
    private File getSettingsDirectory() {
        String userHome = System.getProperty("user.home");
        if(userHome == null) {
            throw new IllegalStateException("user.home==null");
        }
        File home = new File(userHome);
        File settingsDirectory = new File(home, ".clmt");
        if(!settingsDirectory.exists()) {
            if(!settingsDirectory.mkdir()) {
                throw new IllegalStateException(settingsDirectory.toString());
            }
        }
        return settingsDirectory;
    }

    /** Reads in the Craigs List category data from categories.dat */
    public void loadCategoryData() {
        try {
            // Get the settings dir
            File settingsDir = this.getSettingsDirectory();
            // Get the properties file
            File categoriesFile = new File(settingsDir, "categories.dat");
            // Create the properties file if it doesn't exist
            if (!categoriesFile.exists()) {
                this.createResource(categoriesFile, "/resources/categories.dat");
            }
            // Create the hash map
            this.categories = new HashMap();
            FileReader input = new FileReader(categoriesFile);
            BufferedReader bufRead = new BufferedReader(input);
            while (bufRead.ready()) {
                // Get the category
                String[] category = bufRead.readLine().split(":");
                HashMap subTable = new HashMap();
                String[] subcategories = category[1].split(",");
                for (String subcat : subcategories) {
                    String[] keyval = subcat.split("\\|");
                    subTable.put(keyval[0], keyval[1]);
                }
                if (!this.categories.containsKey(category[0])) {
                    this.categories.put(category[0], subTable);
                }
            }
        }
        catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (IOException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /** Reads in the Craigs List city data from cities.dat */
    public void loadCityData() {
        try {
            // Get the settings dir
            File settingsDir = this.getSettingsDirectory();
            // Get the properties file
            File citiesFile = new File(settingsDir, "cities.dat");
            // Create the properties file if it doesn't exist
            if (!citiesFile.exists()) {
                this.createResource(citiesFile, "/resources/cities.dat");
            }
            // Determine the number of cities
            FileReader input = new FileReader(citiesFile);
            BufferedReader bufRead = new BufferedReader(input);
            int lines = 0;
            while (bufRead.ready()) {
                String[] data = bufRead.readLine().split(",");
                if (data.length != 4) continue;
                lines++;
            }
            bufRead.close();
            input.close();
            // Read in data
            input = new FileReader(citiesFile);
            bufRead = new BufferedReader(input);
            this.cities = new String[lines][4];
            lines = 0;
            while (bufRead.ready()) {
                // Get the city
                String[] data = bufRead.readLine().split(",");
                if (data.length != 4) continue;
                this.cities[lines][0] = data[0];
                this.cities[lines][1] = data[1];
                this.cities[lines][2] = data[2];
                this.cities[lines++][3] = data[3];
            }
        }
        catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (IOException ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
        catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "Unknown exception: " + ex.toString(), "Exception", JOptionPane.ERROR_MESSAGE);
        }
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Accessors">
    
    /** Gets the properties object */
    public Properties getProperties() {
        return this.properties;
    }
    
    public String[] getCLCategories() {
        Set keySet = this.categories.keySet();
        return (String[])keySet.toArray(new String[keySet.size()]);
    }
    
    public String[] getCLSubCategories(String category) {
        Set keySet = ((HashMap)this.categories.get(category)).keySet();
        return (String[])keySet.toArray(new String[keySet.size()]);
    }
    
    public String getCLCategoryWebKey(String category, String subCategory) {
        return (String)((HashMap)this.categories.get(category)).get(subCategory);
    }
    
    public DefaultMutableTreeNode getCLCities() {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Cities");
        for (int i = 0; i < this.cities.length; i++) {
            // Get the region node
            DefaultMutableTreeNode regionNode = null;
            for (Enumeration e = root.children(); e.hasMoreElements();) {
                DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)e.nextElement();
                if (((String)childNode.getUserObject()).equals(this.cities[i][0])) { // [0] = region/country
                    regionNode = childNode;
                }
            }
            if (regionNode == null) {
                regionNode = new DefaultMutableTreeNode(this.cities[i][0]);
                root.add(regionNode);
            }
            // Get the area node
            DefaultMutableTreeNode areaNode = null;
            for (Enumeration e = regionNode.children(); e.hasMoreElements();) {
                DefaultMutableTreeNode childNode = (DefaultMutableTreeNode)e.nextElement();
                if (((String)childNode.getUserObject()).equals(this.cities[i][1])) { // [1] = area/state
                    areaNode = childNode;
                }
            }
            if (areaNode == null) {
                areaNode = new DefaultMutableTreeNode(this.cities[i][1]);
                regionNode.add(areaNode);
            }
            // Add the city node
            DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(this.cities[i][2]); // [2] = city name
            areaNode.add(childNode);
        }
        return root;
    }
    
    public JTree getCLCityTree() {
        return new JTree(this.cities);
    }
    // </editor-fold>
}
